import React, { Component } from 'react';
import Styled from 'styled-components';
import { Table, Button, Upload, message } from 'antd';
import { DragSource, DropTarget } from 'react-dnd';
import update from 'immutability-helper';
import http from '@/utils/http';

const Box = Styled.div`
  padding: 24px 20px 0 20px;
  >.btnList {
    button {
      margin: 0 12px 12px 0;
    }     
  }
  tr.drop-over-downward td {
    border-bottom: 2px dashed #18B582;
  }
  tr.drop-over-upward td {
    border-top: 2px dashed #18B582;
  }
`;

let dragingIndex = -1;

class BodyRow extends Component {
  render() {
    const { isOver, connectDragSource, connectDropTarget, moveRow, ...restProps} = this.props;
    const style = { ...restProps.style, cursor: 'move' };
    let className = restProps.className;
    if (isOver) {
      if (restProps.index > dragingIndex) {
        className += ' drop-over-downward';
      }
      if (restProps.index < dragingIndex) {
        className += ' drop-over-upward';
      }
    }

    return connectDragSource(
      connectDropTarget(
        <tr {...restProps} className={className} style={style} />
      )
    );
  }
}

class GridDnd extends Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      uploadLoading: false,
      dataset: [],
      operateBtns: props.operation ? this.setOperateBtns(props.operation) : []
    };
    const rowTarget = {
      drop(props, monitor) {
        const dragIndex = monitor.getItem().index;
        const hoverIndex = props.index;
        // Don't replace items with themselves
        if (dragIndex === hoverIndex) {
          return;
        }
        // Time to actually perform the action
        props.moveRow(dragIndex, hoverIndex);
        // Note: we're mutating the monitor item here!
        // Generally it's better to avoid mutations,
        // but it's good here for the sake of performance
        // to avoid expensive index searches.
        monitor.getItem().index = hoverIndex;
      }
    };
    const rowSource = {
      beginDrag(props) {
        dragingIndex = props.index;
        return {
          index: props.index,
        };
      }
    };
    const DragableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({
        connectDropTarget: connect.dropTarget(),
        isOver: monitor.isOver(),
    }))(
      DragSource('row', rowSource, (connect) => ({
        connectDragSource: connect.dragSource(),
      }))(BodyRow)
    );
    this.components = {
      body: {
        row: DragableBodyRow,
      }
    }
  }

  componentDidMount() {
    const { url, dataSource } = this.props;
    if (url) {
      this.queryList();
    } else if (dataSource) {
      this.setState({ dataset: dataSource });
    }
  }

  componentDidUpdate(prevProps) {
    const { operation } = this.props;
    if (prevProps.operation !== operation && operation.length) {
      this.setState({ operateBtns: this.setOperateBtns(operation) });
    }
  }

  setOperateBtns(list) {
    const btnList = [];
    list.forEach(item => {
      if (item.state === 'add') {
        btnList.push(Object.assign({
          type: 'primary',
          icon: 'plus',
          title: '新增'
        }, item));
      } else if (item.state === 'upload') {
        const onChange = item.props.onChange;
        const props = Object.assign(item.props, {
          onChange: ({file, fileList}) => {
            if (file.status !== 'uploading') {
              this.setState({ uploadLoading: true });
            } else if (file.status === 'done') {
              message.success(`${file.name} 文件上传成功！`);
              this.setState({ uploadLoading: false });
            } else if (file.status === 'error') {
              message.error(`${file.name} 文件上传失败！`);
              this.setState({ uploadLoading: false });
            }
            // eslint-disable-next-line
            onChange?.({file, fileList});
          }
        });
        btnList.push(Object.assign({
          icon: 'upload',
          title: '上传'
        }, item, { props }));
      } else {
        btnList.push(item);
      }
    });
    return btnList;
  }

  queryList() {
    this.setState({ loading: true });
    const { url } = this.props;
    return http.get(url).then(response => {
      this.setState({
        loading: false,
        dataset:  response.data instanceof Array ? response.data : response.data.rows
      });
    });
  }

  // 若存在复选框，获取选中数据
  getSelectedData() {
    // return this.state.selectedList;
  }
  refreshGrid() {
    this.queryList();
  }
  handleMoveRow(dragIndex, hoverIndex) {
    const { fnDrag,isNav } = this.props;
    const { dataset } = this.state;
    const dragRow = dataset[dragIndex];
    if(isNav && (dragRow.code === 'index' || dataset[hoverIndex].code === 'index')){
      message.error("首页不可更改排序")
      return false;
    }
    const temp = update(this.state, {
      dataset: {
        $splice: [[dragIndex, 1], [hoverIndex, 0, dragRow]],
      }
    });
    if (fnDrag) {
      fnDrag(temp.dataset).then(() => {
        this.setState({ dataset: temp.dataset });
      });
    } else {
      this.setState({ dataset: temp.dataset });
    }
  }
  renderOperateBtns(i, idx) {
    if (i.state === 'upload') {
      return <Upload key={idx} {...i.props} ><Button type={i.type} icon={this.state.uploadLoading ? 'loading' : i.icon}>{i.title}</Button></Upload>
    }else{
      return <Button key={idx} type={i.type} onClick={i.onClick} icon={i.icon}>{i.title}</Button>
    }
  }
  
  render() {
    const { loading, dataset, operateBtns } = this.state;
    const { url, dataSource, operation, className, components, onRow, fnDrag, ...params } = this.props;
    return (
      <Box className={className}>
        <div className="btnList">
          {operateBtns.map((i, idx) => this.renderOperateBtns(i, idx))}
        </div>
        <Table className="rs-grid"
          rowKey="id" 
          loading={loading} 
          dataSource={dataset} 
          pagination={false}
          components={this.components} 
          onRow={(record, index) => ({
            index,
            moveRow: this.handleMoveRow.bind(this),
          })}
          {...params} 
        />
      </Box>
    );
  }
}      

export default GridDnd;
